// 提供对数据库以及图片文件系统的操作接口，服务于EncodingHandler.hpp的上层模块
// 接口中的自定义类型包括：
//     <1> 用户相关
//         UserDataType：user_id在Verify接口返回给上层，再由上层移交会话
//     <2> 帖子相关
//         PostDataType：会话需要保存user_id及post_id，用于后续评论、点赞等操作
//     <3> 照片相关
//         PhotoDataType
//     <4> 评论相关
//         CommentDataType
//     <5> 事件相关
//         EventDataType
//     ---------------------------------------------------------------------

#ifndef DB_HANDLER_HPP
#define DB_HANDLER_HPP

#include "sqlhelper.hpp"
#include "log.hpp"
#include "common_types.hpp"
#include <fstream>
#include <mutex>
#include <atomic>

/*
    数据库表定义详见：../source/database/photography_forum.sql
*/

namespace xzt
{
#ifdef FOR_TEST
#define DB_PATHNAME "../../source/database/photography_forum.db"
#define PHOTO_DIR "../../source/photos/"
#else
#define DB_PATHNAME "../source/database/photography_forum.db"
#define PHOTO_DIR "../source/photos/"
#endif

    // 为需要点赞功能的类提供接口
    class HasLiked
    {
    public:
        // object_type可选值：'post', 'photo', 'event'
        static bool judge(const std::string &user_id, const std::string &object_id, const std::string &object_type)
        {
            std::string sql = "SELECT 1 FROM likes WHERE user_id = '" + user_id + "' AND object_id = '" + object_id + "' AND object_type = '" + object_type + "';";
            xzt::SqlHelper helper(DB_PATHNAME);
            bool ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            std::vector<std::string> result;
            helper.query_data(sql, _getHasLiked_FromDB_Callback, &result);
            helper.close();
            return result.size() == 1;
        }

    private:
        static int _getHasLiked_FromDB_Callback(void *arg, int argc, char **argv, char **colName)
        {
            auto result = static_cast<std::vector<std::string> *>(arg);
            result->push_back(argv[0]);
            return 0;
        }
    };

    class PhotoDBHandler
    {
        // 注意：PhotoType是cv::Mat类型，而PhotoDataType是包含图片信息与PhotoType的自定义类型，
    public:
        // 保存图片文件及其信息
        // 参数描述：注意photo对象中无需填充image_path和create_at字段，前者有写回对象操作，后者由数据库自动填充
        static bool SavePhoto(PhotoDataType &photo)
        {
            if (photo.image_binary.empty())
            {
                // 图片本体为空，保存失败
                LOG_ERROR("图片本体ProtoType为空，保存失败！");
                return false;
            }

            std::string photo_pathmame = PHOTO_DIR + std::to_string(PhotoDBHandler::photo_num + 1) + ".jpg";
            photo.image_path = photo_pathmame; // 写回图片路径
            // 保存图片信息到数据库
            bool ret = _saveToDB(photo);
            // 保存图片文件到服务器
            return ret && _saveToFile(photo);
        }

        // 利用图片路径获取图片信息及数据
        static PhotoDataType GetPhoto(const std::string &image_path)
        {
            // 首先判断图片文件是否存在
            std::ifstream ifs(image_path);
            if (!ifs)
            {
                LOG_ERROR("图片文件不存在！");
                return PhotoDataType();
            }

            // 从数据库中获取图片信息组成PhotoType
            xzt::SqlHelper helper(DB_PATHNAME);
            bool ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            std::vector<PhotoDataType> photo_v;
            std::string sql = "SELECT * FROM photos WHERE image_path = '" + image_path + "'";
            helper.query_data(sql, _getPhotoData_FromDB_Callback, &photo_v);
            if (photo_v.size() == 0)
            {
                LOG_FATAL("图片信息不存在！{图片路径：" + image_path + "}");
                helper.close();
                assert(false); // 文件中存在，但数据库中不存在，致命错误，程序终止
            }
            else if (photo_v.size() > 1)
            {
                LOG_FATAL("数据库中存在多个同名图片信息！{图片路径：" + image_path + "}");
                helper.close();
                assert(false); // 数据库中存在多个同名图片信息，程序出错
            }
            else
            {
                // 图片信息存在，从文件中读取图片数据
                LOG_INFO("从文件中读取图片数据成功！{图片路径：" + image_path + "}");
                PhotoDataType photo = photo_v[0]; // 也仅有一个元素
                photo.image_binary = _readPhotoBinaryData(photo.image_path); // 写回图片二进制数据
                helper.close();
                return photo;
            }
        }

        // 利用用户ID获取用户的所有图片信息
        static std::vector<PhotoDataType> GetPhotosByUserID(const std::string &user_id)
        {
            // 从数据库中获取指定"user_id"字段值等于user_id的所有图片信息
            xzt::SqlHelper helper(DB_PATHNAME);
            bool ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            std::vector<PhotoDataType> ret_photos; // 保存符合条件的所有图片文件
            std::string sql = "SELECT * FROM photos WHERE user_id = '" + user_id + "' ORDER BY created_at DESC;";
            helper.query_data(sql, _getPhotoData_FromDB_Callback, &ret_photos);
            // 遍历所有图片路径，从文件中读取图片数据
            for (auto &photo : ret_photos)
            {
                // 从文件中读取图片数据
                photo.image_binary = _readPhotoBinaryData(photo.image_path); // 写回图片二进制数据
                if (photo.image_binary.empty())
                {
                    LOG_FATAL("_getPhotosByFieldName()从文件中读取图片数据失败！{图片路径：" + photo.image_path + "}");
                    assert(false); // 数据库中存在图片信息，但从文件中读取图片数据失败，程序出错
                }
            }
            helper.close();
            return ret_photos;
        }

        // 按时间、点赞量倒序获取所有图片信息
        static std::vector<PhotoDataType> GetAllPhotos_OrderByTime()
        {
            std::string sql = "SELECT * FROM photos ORDER BY created_at DESC;"; // 按时间倒序
            return _getPhotosBySql(sql);
        }
        static std::vector<PhotoDataType> GetAllPhotos_OrderByLikes()
        {
            std::string sql = "SELECT * FROM photos ORDER BY likes DESC;"; // 按点赞量倒序
            return _getPhotosBySql(sql);
        }

        // 按时间、点赞量倒序获取分类下图片信息
        static std::vector<PhotoDataType> GetPhotosByCategory_OrderByTime(const std::string &category)
        {
            std::string sql = "SELECT * FROM photos WHERE category = '" + category + "' ORDER BY created_at DESC;";
            return _getPhotosBySql(sql);
        }
        static std::vector<PhotoDataType> GetPhotosByCategory_OrderByLikes(const std::string &category)
        {
            std::string sql = "SELECT * FROM photos WHERE category = '" + category + "' ORDER BY likes DESC;";
            return _getPhotosBySql(sql);
        }

        // 点赞图片
        static bool LikePhoto(size_t photo_id, size_t user_id)
        {
            // 首先判断用户是否已经点赞过
            if (HasLiked::judge(std::to_string(user_id), std::to_string(photo_id), "photo"))
            {
                LOG_ERROR("用户已经点赞过！{用户ID：" + std::to_string(user_id) + "，图片ID：" + std::to_string(photo_id) + "}");
                return false;
            }

            // 点赞图片
            xzt::SqlHelper helper(DB_PATHNAME);
            bool ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            // 执行点赞活动事件
            std::string sql = "UPDATE photos SET likes = likes + 1 WHERE photo_id = " + std::to_string(photo_id) + ";";
            ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            ret = helper.exec(sql, nullptr, nullptr);
            if (ret)
            {
                // 如果UPDATE成功，则插入一条记录到通用点赞表likes表中
                sql = "INSERT INTO likes (user_id, object_id, object_type) VALUES (" + std::to_string(user_id) + ", " + std::to_string(photo_id) + ", " + std::string("\"photo\"") + ");";
                ret = helper.exec(sql, nullptr, nullptr);
            }

            if (ret)
            {
                LOG_INFO("点赞图片成功！{用户ID：" + std::to_string(user_id) + "，图片ID：" + std::to_string(photo_id) + "}");
            }
            else
            {
                LOG_ERROR("点赞图片失败！{用户ID：" + std::to_string(user_id) + "，图片ID：" + std::to_string(photo_id) + "}");
            }
            helper.close();
            return ret;
        }

        // 删除图片文件及其信息
        static bool DeletePhoto(const std::string &image_path)
        {
            // 从数据库中删除图片信息
            xzt::SqlHelper helper(DB_PATHNAME);
            bool ret = helper.open();
            if (!ret)
            {
                LOG_ERROR("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            ret = helper.delete_data_equal("photos", "image_path", image_path);
            if (ret)
            {
                LOG_INFO("从数据库中删除图片信息成功！{图片路径：" + image_path + "}");
            }
            else
            {
                LOG_ERROR("从数据库中删除图片信息失败！{图片路径：" + image_path + "}");
                helper.close();
                return false;
            }

            // 从服务器中删除图片文件
            ret = (std::remove(image_path.c_str()) == 0); // remove()删除文件成功或文件不存在都返回0
            if (ret)
            {
                LOG_INFO("从服务器中删除图片文件成功！{图片路径：" + image_path + "}");
                // 刷新图片数量
                PhotoDBHandler::photo_num.fetch_sub(1);
            }
            else
            {
                LOG_FATAL("从服务器中删除图片文件失败！{图片路径：" + image_path + "}");
                helper.close();
                // 数据库与服务器数据不一致，致命错误，程序终止
                assert(false); // 运行到这里，说明数据库中图片信息已经删除，但图片文件存在且删除失败，程序出错
            }
            helper.close();
            return ret;
        }

        // 设置与获取图片数量
        static size_t GetPhotoNum()
        {
            return PhotoDBHandler::photo_num.load();
        }
        static void SetPhotoNum(size_t num)
        {
            PhotoDBHandler::photo_num.store(num);
        }

    private:
        // --- 保存 ---
        // photo对象中需要提前填充基本信息：user_id, title, category, image_path
        static bool _saveToDB(const PhotoDataType &photo)
        {
            // 保存图片信息到数据库
            xzt::SqlHelper helper(DB_PATHNAME);
            helper.open();
            auto ret = helper.insert_data("photos", {"user_id", "title", "category", "image_path"},
                                          {photo.user_id, photo.title, photo.category, photo.image_path});
            if (ret)
            {
                LOG_INFO("保存图片信息到数据库成功！");
            }
            else
            {
                LOG_ERROR("保存图片信息到数据库失败！");
            }
            return ret;
        }
        // photo对象中需要提前填充：image_path, image
        // 注意：image_path是图片文件路径，image是cv::Mat类型
        static bool _saveToFile(const PhotoDataType &photo)
        {
            // 保存图片文件到服务器
            bool ret = _writePhotoBinaryData(photo.image_path, photo.image_binary);

            if (ret)
            {
                LOG_INFO("保存图片文件到服务器成功！");
                // 刷新图片数量
                PhotoDBHandler::photo_num.fetch_add(1);
            }
            else
            {
                LOG_ERROR("保存图片文件到服务器失败！");
            }
            return ret;
        }

        // --- 查询 ---
        static int _getPhotoData_FromDB_Callback(void *arg, int col_count, char **col_values, char **col_names)
        {
            // 解析数据
            auto data_v = static_cast<std::vector<PhotoDataType> *>(arg);
            if (data_v == nullptr)
            {
                return -1;
            }

            // 查询到的一行数据中各个字段对应的值
            PhotoDataType data;
            for (int i = 1; i < col_count; ++i)
            {
                data.photo_id = col_values[0];
                data.user_id = col_values[1];
                data.title = col_values[2];
                data.category = col_values[3];
                data.image_path = col_values[4];
                data.created_at = col_values[5];
                data.likes = std::stol(col_values[6]);
            }

            data_v->push_back(data);
            return 0;
        }

        // 作为其他查询接口的统一接口
        static std::vector<PhotoDataType> _getPhotosBySql(const std::string &sql)
        {
            xzt::SqlHelper helper(DB_PATHNAME);
            bool ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            std::vector<PhotoDataType> ret_photos; // 保存符合条件的所有图片文件
            helper.query_data(sql, _getPhotoData_FromDB_Callback, &ret_photos);
            // 遍历所有图片路径，从文件中读取图片数据
            for (auto &photo : ret_photos)
            {
                // 从文件中读取图片数据
                photo.image_binary = _readPhotoBinaryData(photo.image_path); // 写回图片二进制数据
                if (photo.image_binary.empty())
                {
                    LOG_FATAL("_getPhotoData_FromDB_Callback()从文件中读取图片数据失败！{sql：" + sql + "}");
                    assert(false); // 数据库中存在图片信息，但从文件中读取图片数据失败，程序出错
                }
            }
            helper.close();
            return ret_photos;
        }

        // --- 图片源字节流操作辅助函数 ---
        // 图片二进制数据的读取
        static std::vector<char> _readPhotoBinaryData(const std::string &image_path)
        {
            std::ifstream ifs(image_path, std::ios::binary);
            if (!ifs)
            {
                LOG_ERROR("Failed to open file: " + image_path);
                return std::vector<char>();
            }

            // 将文件的读取指针移到文件末尾，计算文件大小
            ifs.seekg(0, std::ios::end);
            std::streamsize size = ifs.tellg();
            ifs.seekg(0, std::ios::beg);

            // 读取文件内容到一个 vector 中
            std::vector<char> buffer(size);
            if (!ifs.read(buffer.data(), size))
            {
                LOG_ERROR("Failed to read file: %s", image_path);
                return std::vector<char>();
            }

            return buffer;
        }
        // 写入图片二进制数据
        static bool _writePhotoBinaryData(const std::string &image_path, const std::vector<char> &data)
        {
            std::ofstream ofs(image_path, std::ios::binary);
            if (!ofs)
            {
                LOG_ERROR("Failed to open file for writing: %s", image_path);
                return false;
            }

            // 写入二进制数据到文件
            ofs.write(data.data(), data.size());

            if (!ofs)
            {
                LOG_ERROR("Failed to write data to file: %s", image_path);
                return false;
            }

            return ofs.good();
        }

    public:
        static std::atomic<size_t> photo_num; // 图片数量
    };
    std::atomic<size_t> PhotoDBHandler::photo_num{0}; // 图片数量

    class UserDBHandler
    {
        // 登录验证后，会话已经保存了当前用户ID，后续用户中心相关操作都可以直接使用当前用户ID
    public:
        // 查询用户信息
        static UserDataType GetUserByName(const std::string &username)
        {
            std::string sql = "SELECT * FROM users WHERE username = '" + username + "';";
            return _getUserBySql(sql);
        }
        static UserDataType GetUserByID(size_t user_id)
        {
            std::string sql = "SELECT * FROM users WHERE user_id = " + std::to_string(user_id) + ";";
            return _getUserBySql(sql);
        }

        // 获取所有用户信息
        static std::vector<UserDataType> GetAllUsers()
        {
            std::vector<UserDataType> user_v;
            xzt::SqlHelper helper(DB_PATHNAME);
            bool ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            std::string sql = "SELECT * FROM users;";
            ret = helper.query_data(sql, _getUserData_FromDB_Callback, &user_v);
            helper.close();

            if (ret)
            {
                return user_v;
            }
            return std::vector<UserDataType>();
        }

        // 查询用户是否存在
        static bool UserExists(const std::string &username)
        {
            return !(GetUserByName(username).username.empty());
        }

        // 注册新用户
        // 返回值：-1表示已存在，0表示失败，1表示成功
        static int RegisterUser(const UserDataType &user)
        {
            // 首先判断用户名是否已存在
            if (UserExists(user.username))
            {
                LOG_ERROR("用户名已存在！{用户名：" + user.username + "}");
                return -1;
            }

            // 保存用户信息到数据库
            xzt::SqlHelper helper(DB_PATHNAME);
            auto ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            ret = helper.insert_data("users", {"username", "password", "email"},
                                     {user.username, user.password, user.email});
            if (ret)
            {
                LOG_INFO("注册新用户成功！{用户名：" + user.username + "}");
            }
            else
            {
                LOG_ERROR("注册新用户失败！{用户名：" + user.username + "}");
            }

            helper.close();
            return ret;
        }

        // 验证用户信息
        // 返回值：0表示验证失败，-1表示账号状态异常，成功则返回user_id
        static int Verify(const std::string &username, const std::string &password)
        {
            // 从数据库中验证用户信息
            xzt::SqlHelper helper(DB_PATHNAME);
            bool ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            std::string sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "';";
            std::vector<UserDataType> user_v;
            helper.query_data(sql, _getUserData_FromDB_Callback, &user_v);
            if (user_v.size() == 0)
            {
                LOG_INFO("用户验证失败！{用户名：" + username + "}");
                helper.close();
                return 0;
            }
            else if (user_v.size() > 1)
            {
                LOG_FATAL("数据库中存在多个同名用户！{用户名：" + username + "}");
                helper.close();
                assert(false); // 数据库中存在多个同名用户，程序出错
            }
            else
            {
                if (user_v[0].status == false)
                {
                    // 账号封禁状态，无法登录
                    LOG_INFO("用户账号已被封禁！{用户名：" + username + "}");
                    helper.close();
                    return -1;
                }

                int user_id = std::stol(user_v[0].user_id);
                LOG_INFO("用户验证成功！{用户名：" + username + ", 用户ID：" + std::to_string(user_id) + "}");
                helper.close();
                return user_id;
            }
        }

        // 修改用户信息
        // 返回值：-1表示用户不存在，0表示失败(用户名重复)，1表示成功
        static int UpdateUser(size_t user_id, const UserDataType &user)
        {
            // 首先判断用户ID是否已存在
            if (!GetUserByID(user_id))
            {
                return -1; // 用户ID对应用户不存在，修改失败
            }

            // 更新用户信息到数据库
            std::string sql = "UPDATE users SET username = '" + user.username + "', password = '" + user.password + "', email = '" + user.email + "' WHERE user_id = " + std::to_string(user_id) + ";";
            return _updateUserBySql(sql);
        }

        // 删除用户
        static bool DeleteUser(size_t user_id)
        {
            // 从数据库中删除用户信息
            xzt::SqlHelper helper(DB_PATHNAME);
            bool ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            ret = helper.delete_data_equal("users", "user_id", std::to_string(user_id));
            if (ret)
            {
                LOG_INFO("从数据库中删除用户信息成功！{用户ID：%d}", user_id);
            }
            else
            {
                LOG_ERROR("从数据库中删除用户信息失败！{用户ID：%d}", user_id);
            }
            return ret;
        }

        // 用户封禁与解封
        // status: 用户状态，1 表示正常，0 表示封禁
        static bool BlockUser(size_t user_id)
        {
            std::string sql = "UPDATE users SET status = 0 WHERE user_id = " + std::to_string(user_id) + ";";
            bool ret = _updateUserBySql(sql);
            if (ret)
            {
                LOG_INFO("用户账号封禁成功！{用户ID：" + std::to_string(user_id) + "}");
            }
            else
            {
                LOG_ERROR("用户账号封禁失败！{用户ID：" + std::to_string(user_id) + "}");
            }
            return ret;
        }
        static bool UnblockUser(size_t user_id)
        {
            std::string sql = "UPDATE users SET status = 1 WHERE user_id = " + std::to_string(user_id) + ";";
            bool ret = _updateUserBySql(sql);
            if (ret)
            {
                LOG_INFO("用户账号解封成功！{用户ID：" + std::to_string(user_id) + "}");
            }
            else
            {
                LOG_ERROR("用户账号解封失败！{用户ID：" + std::to_string(user_id) + "}");
            }
            return ret;
        }

    private:
        static UserDataType _getUserBySql(const std::string &sql)
        {
            xzt::SqlHelper helper(DB_PATHNAME);
            bool ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            std::vector<UserDataType> user_v;
            helper.query_data(sql, _getUserData_FromDB_Callback, &user_v);
            if (user_v.size() == 0)
            {
                LOG_INFO("用户信息不存在！{sql：" + sql + "}");
                helper.close();
                return UserDataType();
            }
            else if (user_v.size() > 1)
            {
                LOG_FATAL("数据库中存在多个同名用户！{sql：" + sql + "}");
                helper.close();
                assert(false); // 数据库中存在多个同名用户，程序出错
            }
            else
            {
                // 用户信息存在，返回
                LOG_INFO("获取用户信息成功！{sql：" + sql + "}");
                helper.close();
                return user_v[0];
            }
        }

        static bool _updateUserBySql(const std::string &sql)
        {
            // 更新用户信息到数据库
            xzt::SqlHelper helper(DB_PATHNAME);
            auto ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            ret = helper.exec(sql, nullptr, nullptr); // 执行UPDATE语句
            if (ret)
            {
                LOG_INFO("更新用户信息成功！{sql：" + sql + "}");
            }
            else
            {
                LOG_ERROR("更新用户信息失败！{sql：" + sql + "}");
            }
            helper.close();
            return ret;
        }

        // --- 解析 ---
        static int _getUserData_FromDB_Callback(void *arg, int col_count, char **col_values, char **col_names)
        {
            // 解析数据
            auto data_v = static_cast<std::vector<UserDataType> *>(arg);
            if (data_v == nullptr)
            {
                return -1;
            }

            // 查询到的一行数据中各个字段对应的值
            UserDataType data;
            data.user_id = col_values[0];
            data.username = col_values[1];
            data.password = col_values[2];
            data.email = col_values[3];
            data.created_at = col_values[4];
            data.status = std::stoi(col_values[5]);

            data_v->push_back(data);
            return 0;
        }
    };

    class PostDBHandler
    {
    public:
        // 保存帖子
        // 注意：post对象中需要提前填充基本信息：user_id, title, content
        static bool SavePost(const PostDataType &post)
        {
            xzt::SqlHelper helper(DB_PATHNAME);
            auto ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            // 保存帖子信息到数据库
            ret = helper.insert_data("posts", {"user_id", "title", "content"},
                                     {post.user_id, post.title, post.content});
            if (ret)
            {
                LOG_INFO("保存帖子信息到数据库成功！{帖子标题：" + post.title + "}");
            }
            else
            {
                LOG_ERROR("保存帖子信息到数据库失败！{帖子标题：" + post.title + "}");
            }
            helper.close();
            return ret;
        }

        // 获取所有帖子（包括按时间倒序和点赞量倒序）
        static std::vector<PostDataType> GetPosts_OrderByTime()
        {
            std::string sql = "SELECT * FROM posts ORDER BY created_at DESC;";
            return _getPostsBySql(sql);
        }
        static std::vector<PostDataType> GetPosts_OrderByLikes()
        {
            std::string sql = "SELECT * FROM posts ORDER BY likes DESC;";
            return _getPostsBySql(sql);
        }

        // 获取指定用户的所有帖子（按时间倒序）
        static std::vector<PostDataType> GetPostsByUserID(size_t user_id)
        {
            std::string sql = "SELECT * FROM posts WHERE user_id = " + std::to_string(user_id) + " ORDER BY created_at DESC;";
            return _getPostsBySql(sql);
        }

        // 删除帖子
        static bool DeletePost(size_t post_id)
        {
            std::string sql = "DELETE FROM posts WHERE post_id = " + std::to_string(post_id) + ";";
            xzt::SqlHelper helper(DB_PATHNAME);
            auto ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            ret = helper.exec(sql, nullptr, nullptr);
            if (ret)
            {
                LOG_INFO("从数据库中删除帖子信息成功！{帖子ID：" + std::to_string(post_id) + "}");
            }
            else
            {
                LOG_ERROR("从数据库中删除帖子信息失败！{帖子ID：" + std::to_string(post_id) + "}");
            }
            helper.close();
            return ret;
        }

        // 点赞帖子
        // 注意：user_id是点赞人对应的user_id
        static bool LikePost(size_t post_id, size_t user_id)
        {
            // 首先判断用户是否已经点赞过
            bool is_liked = xzt::HasLiked::judge(std::to_string(user_id), std::to_string(post_id), "post");
            if (is_liked)
            {
                LOG_INFO("用户已经点赞过该帖子！{帖子ID：" + std::to_string(post_id) + "}");
                return false;
            }

            // 执行点赞帖子
            std::string sql = "UPDATE posts SET likes = likes + 1 WHERE post_id = " + std::to_string(post_id) + ";";
            xzt::SqlHelper helper(DB_PATHNAME);
            auto ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            ret = helper.exec(sql, nullptr, nullptr); // 执行UPDATE语句，更新likes字段
            if (ret)
            {
                // 如果UPDATE成功，则插入一条记录到通用点赞表likes表中
                sql = "INSERT INTO likes (user_id, object_id, object_type) VALUES (" + std::to_string(user_id) + ", " + std::to_string(post_id) + ", " + std::string("\"post\"") + ");";
                ret = helper.exec(sql, nullptr, nullptr);
            }

            if (ret)
            {
                LOG_INFO("点赞帖子成功！{帖子ID：" + std::to_string(post_id) + "}");
            }
            else
            {
                LOG_ERROR("点赞帖子失败！{帖子ID：" + std::to_string(post_id) + "}");
            }
            helper.close();
            return ret;
        }

        // 模糊搜索帖子
        static std::vector<PostDataType> FuzzySearchPost(const std::string &keyword)
        {
            std::string sql = "SELECT * FROM posts WHERE title LIKE '%" + keyword + "%' OR content LIKE '%" + keyword + "%' ORDER BY created_at DESC;";
            return _getPostsBySql(sql);
        }

    private:
        // 传入的sql语句必须是: select *
        static std::vector<PostDataType> _getPostsBySql(const std::string &sql)
        {
            xzt::SqlHelper helper(DB_PATHNAME);
            bool ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            std::vector<PostDataType> post_v; // 保存符合条件的所有帖子
            ret = helper.query_data(sql, _getPostData_FromDB_Callback, &post_v);
            if (ret)
            {
                LOG_INFO("获取帖子信息成功！{sql：" + sql + "}");
            }
            else
            {
                LOG_ERROR("获取帖子信息失败！{sql：" + sql + "}");
            }
            helper.close();

            return post_v;
        }

        static int _getPostData_FromDB_Callback(void *arg, int col_count, char **col_values, char **col_names)
        {
            // 解析数据
            auto data_v = static_cast<std::vector<PostDataType> *>(arg);
            if (data_v == nullptr)
            {
                return -1;
            }

            // 查询到的一行数据中各个字段对应的值
            PostDataType data;
            data.post_id = col_values[0];
            data.user_id = col_values[1];
            data.title = col_values[2];
            data.content = col_values[3];
            data.created_at = col_values[4];
            data.likes = std::stol(col_values[5]);

            data_v->push_back(data);
            return 0;
        }
    };

    class CommentDBHandler
    {
    public:
        // 保存评论（评论归属于帖子）
        // 注意：comment对象中的user_id和post_id对应发布者的user_id不同，除非自己评论自己的帖子
        static bool SaveComment(const CommentDataType &comment)
        {
            xzt::SqlHelper helper(DB_PATHNAME);
            auto ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            // 保存评论信息到数据库
            ret = helper.insert_data("comments", {"post_id", "user_id", "content"},
                                     {comment.post_id, comment.user_id, comment.content});
            if (ret)
            {
                LOG_INFO("保存评论信息到数据库成功！{评论内容：" + comment.content + "}");
            }
            else
            {
                LOG_ERROR("保存评论信息到数据库失败！{评论内容：" + comment.content + "}");
            }
            helper.close();
            return ret;
        }

        // 获取指定帖子的所有评论（按时间倒序）
        static std::vector<CommentDataType> GetCommentsByPostID(size_t post_id)
        {
            xzt::SqlHelper helper(DB_PATHNAME);
            bool ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            std::string sql = "SELECT * FROM comments WHERE post_id = " + std::to_string(post_id) + " ORDER BY created_at DESC;";
            std::vector<CommentDataType> comment_v; // 保存符合条件的所有评论
            ret = helper.query_data(sql, _getCommentData_FromDB_Callback, &comment_v);
            if (ret)
            {
                LOG_INFO("获取评论信息成功！{帖子ID：" + std::to_string(post_id) + "}");
            }
            else
            {
                LOG_ERROR("获取评论信息失败！{帖子ID：" + std::to_string(post_id) + "}");
            }
            helper.close();

            return comment_v;
        }

        // 删除评论
        static bool DeleteComment(size_t comment_id)
        {
            std::string sql = "DELETE FROM comments WHERE comment_id = " + std::to_string(comment_id) + ";";
            xzt::SqlHelper helper(DB_PATHNAME);
            auto ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            ret = helper.exec(sql, nullptr, nullptr);
            if (ret)
            {
                LOG_INFO("从数据库中删除评论信息成功！{评论ID：" + std::to_string(comment_id) + "}");
            }
            else
            {
                LOG_ERROR("从数据库中删除评论信息失败！{评论ID：" + std::to_string(comment_id) + "}");
            }
            helper.close();
            return ret;
        }

    private:
        // 传入的sql语句必须是: select *
        static int _getCommentData_FromDB_Callback(void *arg, int col_count, char **col_values, char **col_names)
        {
            // 解析数据
            auto data_v = static_cast<std::vector<CommentDataType> *>(arg);
            if (data_v == nullptr)
            {
                return -1;
            }

            // 查询到的一行数据中各个字段对应的值
            CommentDataType data;
            data.comment_id = col_values[0];
            data.user_id = col_values[1];
            data.post_id = col_values[2];
            data.content = col_values[3];
            data.created_at = col_values[4];

            data_v->push_back(data);
            return 0;
        }
    };

    class EventDBHandler
    {
    public:
        // 保存活动事件
        static bool SaveEvent(const EventDataType &event)
        {
            xzt::SqlHelper helper(DB_PATHNAME);
            auto ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            // 保存活动事件信息到数据库
            ret = helper.insert_data("events", {"user_id", "title", "description", "location", "event_date"},
                                     {event.user_id, event.title, event.description, event.location, event.event_date});
            if (ret)
            {
                LOG_INFO("保存活动事件信息到数据库成功！{活动标题：" + event.title + "}");
            }
            else
            {
                LOG_ERROR("保存活动事件信息到数据库失败！{活动标题：" + event.title + "}");
            }
            helper.close();
            return ret;
        }

        // 获取所有活动事件（按时间倒序和按点赞量倒序）
        static std::vector<EventDataType> GetEvents_OrderByTime()
        {
            std::string sql = "SELECT * FROM events ORDER BY is_top DESC, created_at DESC;";
            return _getEventsBySql(sql);
        }
        static std::vector<EventDataType> GetEvents_OrderByLikes()
        {
            std::string sql = "SELECT * FROM events ORDER BY likes DESC;";
            return _getEventsBySql(sql);
        }

        // 获取指定用户发布的所有活动事件（按时间倒序）
        static std::vector<EventDataType> GetEventsByUserID(size_t user_id)
        {
            std::string sql = "SELECT * FROM events WHERE user_id = " + std::to_string(user_id) + " ORDER BY created_at DESC;";
            return _getEventsBySql(sql);
        }

        // 删除活动事件
        static bool DeleteEvent(size_t event_id)
        {
            std::string sql = "DELETE FROM events WHERE event_id = " + std::to_string(event_id) + ";";
            xzt::SqlHelper helper(DB_PATHNAME);
            auto ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            ret = helper.exec(sql, nullptr, nullptr);
            if (ret)
            {
                LOG_INFO("从数据库中删除活动事件信息成功！{活动ID：" + std::to_string(event_id) + "}");
            }
            else
            {
                LOG_ERROR("从数据库中删除活动事件信息失败！{活动ID：" + std::to_string(event_id) + "}");
            }
            helper.close();
            return ret;
        }

        // 置顶活动事件
        static bool TopEvent(size_t event_id)
        {
            std::string sql = "UPDATE events SET is_top = 1 WHERE event_id = " + std::to_string(event_id) + ";";
            xzt::SqlHelper helper(DB_PATHNAME);
            auto ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            ret = helper.exec(sql, nullptr, nullptr);
            if (ret)
            {
                LOG_INFO("置顶活动事件成功！{活动ID：" + std::to_string(event_id) + "}");
            }
            else
            {
                LOG_ERROR("置顶活动事件失败！{活动ID：" + std::to_string(event_id) + "}");
            }
            helper.close();
            return ret;
        }

        // 取消置顶活动事件
        static bool UntopEvent(size_t event_id)
        {
            std::string sql = "UPDATE events SET is_top = 0 WHERE event_id = " + std::to_string(event_id) + ";";
            xzt::SqlHelper helper(DB_PATHNAME);
            auto ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            ret = helper.exec(sql, nullptr, nullptr);
            if (ret)
            {
                LOG_INFO("取消置顶活动事件成功！{活动ID：" + std::to_string(event_id) + "}");
            }
            else
            {
                LOG_ERROR("取消置顶活动事件失败！{活动ID：" + std::to_string(event_id) + "}");
            }
            helper.close();
            return ret;
        }

        // 点赞活动事件
        static bool LikeEvent(size_t event_id, size_t user_id)
        {
            // 先判断用户是否已经点赞过
            bool is_liked = xzt::HasLiked::judge(std::to_string(user_id), std::to_string(event_id), "event");
            if (is_liked)
            {
                LOG_INFO("用户已经点赞过该活动！{活动ID：" + std::to_string(event_id) + "}");
                return false;
            }

            // 执行点赞活动事件
            std::string sql = "UPDATE events SET likes = likes + 1 WHERE event_id = " + std::to_string(event_id) + ";";
            xzt::SqlHelper helper(DB_PATHNAME);
            auto ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            ret = helper.exec(sql, nullptr, nullptr);
            if (ret)
            {
                // 如果UPDATE成功，则插入一条记录到通用点赞表likes表中
                sql = "INSERT INTO likes (user_id, object_id, object_type) VALUES (" + std::to_string(user_id) + ", " + std::to_string(event_id) + ", " + std::string("\"event\"") + ");";
                ret = helper.exec(sql, nullptr, nullptr);
            }

            if (ret)
            {
                LOG_INFO("点赞活动事件成功！{活动ID：" + std::to_string(event_id) + "}");
            }
            else
            {
                LOG_ERROR("点赞活动事件失败！{活动ID：" + std::to_string(event_id) + "}");
            }
            helper.close();
            return ret;
        }

        // 模糊搜索活动事件
        static std::vector<EventDataType> FuzzySearchEvent(const std::string &keyword)
        {
            std::string sql = "SELECT * FROM events WHERE title LIKE '%" + keyword + "%' OR description LIKE '%" + keyword + "%' ORDER BY created_at DESC;";
            return _getEventsBySql(sql);
        }

    private:
        // 传入的sql语句必须是: select *
        static std::vector<EventDataType> _getEventsBySql(const std::string &sql)
        {
            xzt::SqlHelper helper(DB_PATHNAME);
            bool ret = helper.open();
            if (!ret)
            {
                LOG_FATAL("打开数据库失败！");
                assert(false); // 打开数据库失败，程序出错
            }

            std::vector<EventDataType> event_v; // 保存符合条件的所有活动事件
            ret = helper.query_data(sql, _getEventData_FromDB_Callback, &event_v);
            if (ret)
            {
                LOG_INFO("获取活动事件信息成功！{sql：" + sql + "}");
            }
            else
            {
                LOG_ERROR("获取活动事件信息失败！{sql：" + sql + "}");
            }
            helper.close();

            return event_v;
        }

        static int _getEventData_FromDB_Callback(void *arg, int col_count, char **col_values, char **col_names)
        {
            // 解析数据
            auto data_v = static_cast<std::vector<EventDataType> *>(arg);
            if (data_v == nullptr)
            {
                return -1;
            }

            // 查询到的一行数据中各个字段对应的值
            EventDataType data;
            data.event_id = col_values[0];
            data.user_id = col_values[1];
            data.title = col_values[2];
            data.description = col_values[3];
            data.location = col_values[4];
            data.event_date = col_values[5];
            data.created_at = col_values[6];
            data.is_top = std::stoi(col_values[7]);
            data.likes = std::stol(col_values[8]);

            data_v->push_back(data);
            return 0;
        }
    };
}

#endif // DB_HANDLER_HPP